
package sk.stuba.fei.ut.snmpmanager;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.TransportMapping;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.UdpAddress;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultUdpTransportMapping;

import android.util.Log;

public class SNMPHelper
{
	private static final String TAG = "SNMPHelper";
	// IPv4 regular expression pattern
	private static final String PATTERN = "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
			+ "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
			+ "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
			+ "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";

	public static final String BADOID = "1";
	public static final String BADTARGET = "2";
	public static final String TIMEOUT = "3";

	public static Snmp sSnmp;
	public static CommunityTarget sComtarget;
	static PDU sPdu;

	// sets up CommunityTarget
	private static boolean setupTarget( Agent agent )
	{
		sComtarget = new CommunityTarget();

		if ( agent.getCommunity() != null )
		{
			sComtarget.setCommunity( new OctetString( agent.getCommunity() ) );
		}
		else
		{
			return false;
		}

		if ( isValidSNMPVersion( agent.getVersion() ) )
		{
			sComtarget.setVersion( agent.getVersion() );
		}
		else
		{
			return false;
		}
		
		if ( isValidIpv4Address( agent.getIpv4Address() ) == true
				&& isValidPortNumber( agent.getPort() ) == true )
		{
			sComtarget.setAddress( new UdpAddress( agent.getIpv4Address() + "/"
					+ agent.getPort() ) );
		}
		else
		{
			return false;
		}

		sComtarget.setRetries( 3 );
		sComtarget.setTimeout( 1000 );
		return true;
	}

	// Prepare PDU
	private static PDU preparePDU( String lOid )
	{
		VariableBinding req = new VariableBinding();
		OID oid = new OID( lOid );
		PDU pdu = new PDU();

		req.setOid( oid );
		pdu.add( req );

		return pdu;
	}

	public static String sendGetRequest( Agent agent, String oid )
			throws Exception
	{

		@SuppressWarnings( "rawtypes" )
		TransportMapping transport = new DefaultUdpTransportMapping();
		transport.listen();

		if ( setupTarget( agent ) == true )
		{
			if ( isValidOid( oid ) == true )
			{
				sPdu = preparePDU( oid );
				sSnmp = new Snmp( transport );
				Log.i( TAG, "Sending Request to Agent " + agent.getTitle() );

				ResponseEvent response = sSnmp.get( sPdu, sComtarget );

				// Process Agent Response
				if ( response != null )
				{
					Log.i( TAG, "Got Response from Agent: " + agent.getTitle() );
					PDU responsePDU = response.getResponse();
					if ( responsePDU != null )
					{
						int errorStatus = responsePDU.getErrorStatus();
						int errorIndex = responsePDU.getErrorIndex();
						String errorStatusText = responsePDU
								.getErrorStatusText();

						if ( errorStatus == PDU.noError )
						{
							Log.i( TAG,
									"Snmp Get Response = "
											+ responsePDU.getVariableBindings() );
							sSnmp.close();
							return responsePDU.get( 0 ).getVariable()
									.toString();
						}
						else
						{
							Log.i( TAG, "Error: Request Failed" );
							Log.i( TAG, "Error Status = " + errorStatus );
							Log.i( TAG, "Error Index = " + errorIndex );
							Log.i( TAG, "Error Status Text = "
									+ errorStatusText );
							sSnmp.close();
							return errorStatusText;
						}

					}
					else
					{
						Log.i( TAG, "Error: Response PDU is null" );
						sSnmp.close();
						return R.string.snmpHelper_noResponse + agent.getIpv4Address() + ":"
								+ agent.getPort();
					}
				}
				else
				{
					Log.i( TAG, "Error: Agent Timeout... " );
					sSnmp.close();
					return TIMEOUT;
				}
			}
			else
			{
				// OID value is bad
				return BADOID;
			}

		}
		else
		{
			// Ipv4 address or port or version is bad or community is null
			return BADTARGET;
		}

	}

	/**
	 * 
	 * @param address
	 * @return true if valid IPv4 address in dotted decimal notation
	 */
	public static boolean isValidIpv4Address( final String address )
	{
		Pattern pattern = Pattern.compile( PATTERN );
		Matcher matcher = pattern.matcher( address );
		return matcher.matches();
	}

	/**
	 * 
	 * @param port - 16bit number represented in decimal String
	 * @return true if valid port number
	 */
	public static boolean isValidPortNumber( final String port )
	{
		try
		{
			int portNumber = Integer.valueOf( port );
			if ( portNumber >= 1 && portNumber <= 65535 )
			{
				return true;
			}
			else
			{
				return false;
			}
		}
		catch ( NumberFormatException e )
		{
			return false;
		}

	}

	public static boolean isValidOid( final String oidString )
	{
		OID oid = new OID( oidString );
		return oid.isValid();
	}

	/**
	 * 
	 * @param version - version of SNMP protocol to be used
	 * @return true if one of SnmpConstants.version1/ .version2c/ .version3
	 */
	public static boolean isValidSNMPVersion( final int version )
	{
		if ( version == SnmpConstants.version1
				|| version == SnmpConstants.version2c
				|| version == SnmpConstants.version3 )
		{
			return true;
		}
		else
			return false;

	}

}
